/*
 * Copyright (c) 2002-2017 Huha City Group Holding Limited. All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package me.huha.zhime.pay.util;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import me.huha.zhime.pay.config.WeChatConfig;
import me.huha.zhime.utils.MD5Util;
import me.huha.zhime.utils.Util;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.google.gson.JsonObject;

public class WeChatUtil {

	private static Logger logger = Logger.getLogger(WeChatUtil.class);

	@SuppressWarnings({ "rawtypes", "deprecation" })
	public static JsonObject doXMLPost(String xmlString) {
		CloseableHttpClient client = HttpClients.createDefault();
		String responseText = "";
		CloseableHttpResponse response = null;
		try {
			HttpPost method = new HttpPost(WeChatConfig.prepay_url);
			StringEntity se = new StringEntity(xmlString, "text/html", "UTF-8");
			method.setEntity(se);
			method.setHeader("Content-Type", "text/xml;charset=UTF-8");
			response = client.execute(method);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				responseText = EntityUtils.toString(entity, "UTF-8");
			}
		} catch (Exception e) {
			logger.error("", e);
		} finally {
			try {
				response.close();
			} catch (Exception e) {
				logger.error("", e);
			}
		}
		JsonObject jo = null;
		if (!"".equals(responseText)) {
			try {
				// 对放回结果进行封装
				Document document = DocumentHelper.parseText(responseText);
				Element root = document.getRootElement();
				jo = new JsonObject();
				SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
				for (Iterator it = root.elementIterator(); it.hasNext();) {
					Element element = (Element) it.next();
					String n = element.getName();
					String v = element.getText();
					jo.addProperty(n, v);
					parameters.put(n, v);
				}

				if ("SUCCESS".equals(parameters.get("return_code"))) {
					// 返回成功
					// 校验结果来源的合法性-本地前面和回来的签名进行比较
					String sign = getSign(parameters);
					if (!sign.equals(jo.get("sign"))) {
						jo.addProperty("is_pass_sign_check", "0");
						logger.info("签名检查成功");
					} else {
						jo.addProperty("is_pass_sign_check", "1");
						logger.info("签名检查失败");
					}
				}

			} catch (DocumentException e) {
				logger.error("", e);
			}
		}
		return jo;
	}

	@SuppressWarnings({ "rawtypes", "deprecation" })
	public static JsonObject doXMLPost4OrderQuery(String xmlString) {
		CloseableHttpClient client = HttpClients.createDefault();
		String responseText = "";
		CloseableHttpResponse response = null;
		try {
			HttpPost method = new HttpPost(WeChatConfig.orderquery_url);
			StringEntity se = new StringEntity(xmlString, "text/html", "UTF-8");
			method.setEntity(se);
			method.setHeader("Content-Type", "text/xml;charset=UTF-8");
			response = client.execute(method);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				responseText = EntityUtils.toString(entity, "UTF-8");
			}
		} catch (Exception e) {
			logger.error("", e);
		} finally {
			try {
				response.close();
			} catch (Exception e) {
				logger.error("", e);
			}
		}
		JsonObject jo = null;
		if (!"".equals(responseText)) {
			try {
				// 对放回结果进行封装
				Document document = DocumentHelper.parseText(responseText);
				Element root = document.getRootElement();
				jo = new JsonObject();
				SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
				for (Iterator it = root.elementIterator(); it.hasNext();) {
					Element element = (Element) it.next();
					String n = element.getName();
					String v = element.getText();
					jo.addProperty(n, v);
					parameters.put(n, v);
				}

				if ("SUCCESS".equals(parameters.get("return_code"))) {
					// 返回成功
					// 校验结果来源的合法性-本地前面和回来的签名进行比较
					String sign = getSign(parameters);
					if (!sign.equals(jo.get("sign"))) {
						jo.addProperty("is_pass_sign_check", "0");
						logger.info("签名检查成功");
					} else {
						jo.addProperty("is_pass_sign_check", "1");
						logger.info("签名检查失败");
					}
				}

			} catch (DocumentException e) {
				logger.error("", e);
			}
		}
		return jo;
	}

	@SuppressWarnings("rawtypes")
	public static String getSign4Jsapi(SortedMap<Object, Object> parameters) {
		StringBuffer sb = new StringBuffer();
		Set es = parameters.entrySet();// 所有参与传参的参数按照accsii排序（升序）
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			Object v = entry.getValue();
			sb.append(k + "=" + v + "&");
		}
		String sbs1 = sb.toString();
		sbs1 = sbs1.substring(0, sbs1.length() - 1);
		String sbs2 = DigestUtils.sha1Hex(sbs1);
		return sbs2;
	}

	// 微信订单查询
	public static JsonObject orderQuery(Map<String, Object> param) {
		logger.info("微信订单查询-----------------------");
		String out_trade_no = (String) param.get("out_trade_no");

		SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
		parameters.put("appid", WeChatConfig.appid);
		parameters.put("mch_id", WeChatConfig.mch_id);
		parameters.put("out_trade_no", out_trade_no);
		parameters.put("nonce_str", Util.getUUID());
		parameters.put("sign", WeChatUtil.getSign(parameters));

		StringBuffer sqlSB = new StringBuffer();
		sqlSB.append("<xml> \n");
		sqlSB.append("   <appid>" + parameters.get("appid") + "</appid> \n");
		sqlSB.append("   <mch_id>" + parameters.get("mch_id") + "</mch_id> \n");
		sqlSB.append("   <nonce_str>" + parameters.get("nonce_str")
				+ "</nonce_str> \n");
		sqlSB.append("   <out_trade_no>" + parameters.get("out_trade_no")
				+ "</out_trade_no> \n");
		sqlSB.append("   <sign>" + parameters.get("sign") + "</sign> \n");
		sqlSB.append("</xml> \n");
		JsonObject jo = WeChatUtil.doXMLPost4OrderQuery(sqlSB.toString());
		logger.info(jo);
		return jo;
	}

	// 扫码支付签名
	@SuppressWarnings("rawtypes")
	public static String getSign(SortedMap<Object, Object> parameters) {
		StringBuffer sb = new StringBuffer();
		Set es = parameters.entrySet();// 所有参与传参的参数按照accsii排序（升序）
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			Object v = entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k)
					&& !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + WeChatConfig.key);

		String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
		return sign;
	}

	// pc端微信扫码支付申请
	public static JsonObject payPrepay(SortedMap<Object, Object> parameters) {
		parameters.put("appid", WeChatConfig.appid);
		parameters.put("mch_id", WeChatConfig.mch_id);
		parameters.put("nonce_str", Util.getUUID());
		parameters.put("notify_url", WeChatConfig.notify_url);
		// JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付
		parameters.put("trade_type", "NATIVE");
		parameters.put("sign", WeChatUtil.getSign(parameters));

		String xml = WeChatUtil.getXml(parameters);
		JsonObject jo = WeChatUtil.doXMLPost(xml);
		return jo;
	}

	@SuppressWarnings("rawtypes")
	private static String getXml(SortedMap<Object, Object> parameters) {
		Set es = parameters.entrySet();// 所有参与传参的参数按照accsii排序（升序）
		Iterator it = es.iterator();
		StringBuffer sqlSB = new StringBuffer();
		sqlSB.append("<xml> \n");
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			Object v = entry.getValue();
			if (null != v && !"".equals(v)) {
				sqlSB.append("   <" + k + ">" + v + "</" + k + "> \n");
			}
		}
		sqlSB.append("</xml> \n");
		return sqlSB.toString();
	}
}
